<!DOCTYPE html>
<html>

  <head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  <title>安卓自定义View进阶-Path之完结篇</title>
  <meta name="description" content="Path完结篇，自定义View2D绘图部分Path，主要讲解Path的操作方法，包括：相对方法，填充模式，布尔运算，边界计算以及reset与rewind的区别。">
  <meta name="author" content="GcsSloop">
  <meta name="keywords" content="Path, rMoveTo, rLineTo, rQuadTo, rCubicTo, setFillType, getFillType, isInverseFillType, toggleInverseFillType, incReserve, op, computeBounds, reset, rewind, 自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">
  <meta name="关键字" content="Path, rMoveTo, rLineTo, rQuadTo, rCubicTo, setFillType, getFillType, isInverseFillType, toggleInverseFillType, incReserve, op, computeBounds, reset, rewind, 自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">
  

  <meta name="twitter:card" content="summary">
  <meta name="twitter:title" content="安卓自定义View进阶-Path之完结篇">
  <meta name="twitter:description" content="Path完结篇，自定义View2D绘图部分Path，主要讲解Path的操作方法，包括：相对方法，填充模式，布尔运算，边界计算以及reset与rewind的区别。">
  <meta name="twitter:keywords" content="Path, rMoveTo, rLineTo, rQuadTo, rCubicTo, setFillType, getFillType, isInverseFillType, toggleInverseFillType, incReserve, op, computeBounds, reset, rewind, 自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">
  
  <meta property="og:type" content="article">
  <meta property="og:title" content="安卓自定义View进阶-Path之完结篇">
  <meta property="og:description" content="Path完结篇，自定义View2D绘图部分Path，主要讲解Path的操作方法，包括：相对方法，填充模式，布尔运算，边界计算以及reset与rewind的区别。">
  <meta name="og:keywords" content="Path, rMoveTo, rLineTo, rQuadTo, rCubicTo, setFillType, getFillType, isInverseFillType, toggleInverseFillType, incReserve, op, computeBounds, reset, rewind, 自定义View详解, 自定义控件, 安卓, Android, CustomView, GcsSloop">

  <meta name="theme-color" content="#343434">
  
  <link rel="icon" type="image/png" href="https://raw.githubusercontent.com/GcsSloop/gcssloop.github.io/master/assets/siteinfo/favicon.png" />
  <link href="https://raw.githubusercontent.com/GcsSloop/gcssloop.github.io/master/assets/siteinfo/favicon.png" rel="shortcut icon" type="image/png">
  
  <link href="//netdna.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
  <link rel="stylesheet" href="/css/main.css">

  <link rel="canonical" href="http://www.gcssloop.com/customview/Path_Over">
  <link rel="alternate" type="application/rss+xml" title="GcsSloop" href="http://www.gcssloop.com/feed.xml">
  
  <meta name="google-site-verification" content="Z_g58PkzRAyBMxkqrcDdWrTBK8oOWM-7rUHauhLNF2E" />
  <meta name="baidu-site-verification" content="kUtTXCKaZs" />
  <meta name="baidu-site-verification" content="6DuDv3aaJX" />
  
  <!--阅读次数统计-->
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"> </script>
  
  <!--Fuck Weixin and Baidu-->
  <meta http-equiv="Cache-Control" content="no-transform">
  <meta http-equiv=”Cache-Control” content=”no-siteapp” />
  <meta name="applicable-device" content="pc,mobile">
  <meta name="HandheldFriendly" content="true"/>

  <!-- Google Ad -->
  <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
  <script>
    (adsbygoogle = window.adsbygoogle || []).push({
      google_ad_client: "ca-pub-2767831356529421",
      enable_page_level_ads: true
    });
  </script>

</head>


  <body>

    <span class="mobile btn-mobile-menu">
        <i class="fa fa-list btn-mobile-menu__icon"></i>
        <i class="fa fa-angle-up btn-mobile-close__icon hidden"></i>
    </span>
    
    <header class="panel-cover panel-cover--collapsed" style="background-image: url('/assets/siteinfo/background-cover.jpg')">
  <div class="panel-main">

    <div class="panel-main__inner panel-inverted">
    <div class="panel-main__content">

        <a href="/#blog" title="前往 GcsSloop 的主页" class="blog-button"><img src="/assets/siteinfo/avatar.jpg" width="80" alt="GcsSloop logo" class="panel-cover__logo logo" /></a>
        <h1 class="panel-cover__title panel-title"><a href="/#blog" title="link to homepage for GcsSloop" class="blog-button">GcsSloop</a></h1>

        
        <span class="panel-cover__subtitle panel-subtitle">Just do IT later.</span>
        
        <hr class="panel-cover__divider" />
        <p class="panel-cover__description">嗨，我是 GcsSloop，一名来自2.5次元的魔法师，Android自定义View系列文章作者，非著名程序员。</p>
        <hr class="panel-cover__divider panel-cover__divider--secondary" />
        
        
        <p class="panel-cover__description">欢迎来到我的魔法世界!</p>
        
        
        <div class="navigation-wrapper">
          <div>
            <nav class="cover-navigation cover-navigation--primary">
              <ul class="navigation">
                <li class="navigation__item"><a href="/#blog" title="访问博客" class="blog-button">博客</a></li>
                
                  
                    <li class="navigation__item"><a href="https://github.com/GcsSloop" target="_blank" title="GcsSloop's GitHub">GitHub</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/timeline" title="博客目录">目录</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="https://xiaozhuanlan.com/u/GcsSloop" target="_blank" title="小专栏">专栏</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/category/customview" title="自定义View教程目录">自定义控件</a></li>
                  
                  
                
                  
                    <li class="navigation__item"><a href="/friends" title="友链">友链</a></li>
                  
                  
                
              </ul>
            </nav>
          </div>
          
          <div><nav class="cover-navigation navigation--social">
  <ul class="navigation">

  
  <!-- Weibo -->
  <li class="navigation__item">
    <a href="http://weibo.com/GcsSloop" title="@GcsSloop 的微博" target="_blank">
      <i class='social fa fa-weibo'></i>
      <span class="label">Weibo</span>
    </a>
  </li>
  

  
  <!-- Github -->
  <li class="navigation__item">
    <a href="https://github.com/GcsSloop" title="@GcsSloop 的 Github" target="_blank">
      <i class='social fa fa-github'></i>
      <span class="label">Github</span>
    </a>
  </li>
  
  
  
  <!-- Twitter -->
  <li class="navigation__item">
    <a href="http://twitter.com/GcsSloop" title="@GcsSloop" target="_blank">
      <i class='social fa fa-twitter'></i>
      <span class="label">Twitter</span>
    </a>
  </li>
  

    

  

  
  <!-- RSS -->
  <li class="navigation__item">
    <a href="/feed.xml" rel="author" title="RSS" target="_blank">
      <i class='social fa fa-rss'></i>
      <span class="label">RSS</span>
    </a>
  </li>
  

  
  <!-- Email -->
  <li class="navigation__item">
    <a href="mailto:GcsSloop@gmail.com" title="发邮件给我">
      <i class='social fa fa-envelope'></i>
      <span class="label">Email</span>
    </a>
  </li>
  

  
  <!-- Copyright -->
  <li class="navigation__item">
    <a href="http://choosealicense.online" title="选择版权"  target="_blank">
      <i class="social fa fa-copyright"></i>
      <span class="label">版权</span>
    </a>
  </li>
  
  
  </ul>
</nav>
</div>
        </div>
      </div>
    </div>
    
    
    <div class="panel-cover--overlay cover-slate"></div>
    
  </div>
</header>


    <div class="content-wrapper">
        <div class="content-wrapper__inner">
            <article class="post-container post-container--single" itemscope itemtype="http://schema.org/BlogPosting">
  <header class="post-header">
    <div class="post-meta" style="font-size:.8em">
      <time datetime="2016-05-02 00:00:00 +0800" itemprop="datePublished" class="post-meta__date date">2016-05-02</time> &#8226; <span class="post-meta__tags tags">自定义View,Path,布尔运算</span> &#8226; View <span id="busuanzi_value_page_pv"></span> times.
</span>
    </div>
    <h1 class="post-title">安卓自定义View进阶-Path之完结篇</h1>
  </header>

  <section class="post">
    <p>经历过前两篇 <a href="http://www.gcssloop.com/customview/Path_Basic">Path之基本操作</a> 和 <a href="http://www.gcssloop.com/customview/Path_Bezier">Path之贝塞尔曲线</a> 的讲解，本篇终于进入Path的收尾篇，本篇结束后Path的大部分相关方法都已经讲解完了，但Path还有一些更有意思的玩法，应该会在后续的文章中出现。</p>

<hr />

<h2 id="一path常用方法表">一.Path常用方法表</h2>

<blockquote>
  <p>为了兼容性(<em>偷懒</em>) 本表格中去除了在API21(即安卓版本5.0)以上才添加的方法。忍不住吐槽一下，为啥看起来有些顺手就能写的重载方法要等到API21才添加上啊。宝宝此刻内心也是崩溃的。</p>
</blockquote>

<table>
  <thead>
    <tr>
      <th>作用</th>
      <th>相关方法</th>
      <th>备注</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>移动起点</td>
      <td>moveTo</td>
      <td>移动下一次操作的起点位置</td>
    </tr>
    <tr>
      <td>设置终点</td>
      <td>setLastPoint</td>
      <td>重置当前path中最后一个点位置，如果在绘制之前调用，效果和moveTo相同</td>
    </tr>
    <tr>
      <td>连接直线</td>
      <td>lineTo</td>
      <td>添加上一个点到当前点之间的直线到Path</td>
    </tr>
    <tr>
      <td>闭合路径</td>
      <td>close</td>
      <td>连接第一个点连接到最后一个点，形成一个闭合区域</td>
    </tr>
    <tr>
      <td>添加内容</td>
      <td>addRect, addRoundRect,  addOval, addCircle, 	addPath, addArc, arcTo</td>
      <td>添加(矩形， 圆角矩形， 椭圆， 圆， 路径， 圆弧) 到当前Path (注意addArc和arcTo的区别)</td>
    </tr>
    <tr>
      <td>是否为空</td>
      <td>isEmpty</td>
      <td>判断Path是否为空</td>
    </tr>
    <tr>
      <td>是否为矩形</td>
      <td>isRect</td>
      <td>判断path是否是一个矩形</td>
    </tr>
    <tr>
      <td>替换路径</td>
      <td>set</td>
      <td>用新的路径替换到当前路径所有内容</td>
    </tr>
    <tr>
      <td>偏移路径</td>
      <td>offset</td>
      <td>对当前路径之前的操作进行偏移(不会影响之后的操作)</td>
    </tr>
    <tr>
      <td>贝塞尔曲线</td>
      <td>quadTo, cubicTo</td>
      <td>分别为二次和三次贝塞尔曲线的方法</td>
    </tr>
    <tr>
      <td>rXxx方法</td>
      <td>rMoveTo, rLineTo, rQuadTo, rCubicTo</td>
      <td><strong>不带r的方法是基于原点的坐标系(偏移量)， rXxx方法是基于当前点坐标系(偏移量)</strong></td>
    </tr>
    <tr>
      <td>填充模式</td>
      <td>setFillType, getFillType, isInverseFillType, toggleInverseFillType</td>
      <td>设置,获取,判断和切换填充模式</td>
    </tr>
    <tr>
      <td>提示方法</td>
      <td>incReserve</td>
      <td>提示Path还有多少个点等待加入<strong>(这个方法貌似会让Path优化存储结构)</strong></td>
    </tr>
    <tr>
      <td>布尔操作(API19)</td>
      <td>op</td>
      <td>对两个Path进行布尔运算(即取交集、并集等操作)</td>
    </tr>
    <tr>
      <td>计算边界</td>
      <td>computeBounds</td>
      <td>计算Path的边界</td>
    </tr>
    <tr>
      <td>重置路径</td>
      <td>reset, rewind</td>
      <td>清除Path中的内容<br /> <strong>reset不保留内部数据结构，但会保留FillType.</strong><br /> <strong>rewind会保留内部的数据结构，但不保留FillType</strong></td>
    </tr>
    <tr>
      <td>矩阵操作</td>
      <td>transform</td>
      <td>矩阵变换</td>
    </tr>
  </tbody>
</table>

<h2 id="二path方法详解">二、Path方法详解</h2>

<h3 id="rxxx方法">rXxx方法</h3>

<p>此类方法可以看到和前面的一些方法看起来很像，只是在前面多了一个r，那么这个rXxx和前面的一些方法有什么区别呢？</p>

<blockquote>
  <p><strong>rXxx方法的坐标使用的是相对位置(基于当前点的位移)，而之前方法的坐标是绝对位置(基于当前坐标系的坐标)。</strong></p>
</blockquote>

<p><strong>举个例子:</strong></p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Path</span> <span class="n">path</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>

<span class="n">path</span><span class="o">.</span><span class="na">moveTo</span><span class="o">(</span><span class="mi">100</span><span class="o">,</span><span class="mi">100</span><span class="o">);</span>
<span class="n">path</span><span class="o">.</span><span class="na">lineTo</span><span class="o">(</span><span class="mi">100</span><span class="o">,</span><span class="mi">200</span><span class="o">);</span>

<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">path</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>
</code></pre>
</div>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071449.jpg?gcssloop" alt="" /></p>

<p>在这个例子中，先移动点到坐标(100，100)处，之后再连接 <em>点(100，100)</em> 到 <em>(100，200)</em> 之间点直线,非常简单，画出来就是一条竖直的线，那接下来看下一个例子：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">Path</span> <span class="n">path</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>

<span class="n">path</span><span class="o">.</span><span class="na">moveTo</span><span class="o">(</span><span class="mi">100</span><span class="o">,</span><span class="mi">100</span><span class="o">);</span>
<span class="n">path</span><span class="o">.</span><span class="na">rLineTo</span><span class="o">(</span><span class="mi">100</span><span class="o">,</span><span class="mi">200</span><span class="o">);</span>

<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">path</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>
</code></pre>
</div>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071450.jpg?gcssloop" alt="" /></p>

<p>这个例子中，将 lineTo 换成了 rLineTo 可以看到在屏幕上原本是竖直的线变成了倾斜的线。这是因为最终我们连接的是 <em>(100,100)</em> 和 <em>(200, 300)</em> 之间的线段。</p>

<p>在使用rLineTo之前，当前点的位置在 (100,100) ， 使用了 rLineTo(100,200) 之后，下一个点的位置是在当前点的基础上加上偏移量得到的，即 (100+100, 100+200) 这个位置，故最终结果如上所示。</p>

<p><strong>PS: 此处仅以 rLineTo 为例，只要理解 “绝对坐标” 和 “相对坐标” 的区别，其他方法类比即可。</strong></p>

<h3 id="填充模式">填充模式</h3>

<p>我们在之前的文章中了解到，Paint有三种样式，“描边” “填充” 以及 “描边加填充”，我们这里所了解到就是在Paint设置为后两种样式时<strong>不同的填充模式对图形渲染效果的影响</strong>。</p>

<p><strong>我们要给一个图形内部填充颜色，首先需要分清哪一部分是外部，哪一部分是内部，机器不像我们人那么聪明，机器是如何判断内外呢？</strong></p>

<p>机器判断图形内外，一般有以下两种方法：</p>

<blockquote>
  <p>PS：此处所有的图形均为封闭图形，不包括图形不封闭这种情况。</p>
</blockquote>

<table>
  <thead>
    <tr>
      <th>方法</th>
      <th>判定条件</th>
      <th>解释</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>奇偶规则</td>
      <td>奇数表示在图形内，偶数表示在图形外</td>
      <td>从任意位置p作一条射线， 若与该射线相交的图形边的数目为奇数，则p是图形内部点，否则是外部点。</td>
    </tr>
    <tr>
      <td>非零环绕数规则</td>
      <td>若环绕数为0表示在图形外，非零表示在图形内</td>
      <td>首先使图形的边变为矢量。将环绕数初始化为零。再从任意位置p作一条射线。当从p点沿射线方向移动时，对在每个方向上穿过射线的边计数，每当图形的边从右到左穿过射线时，环绕数加1，从左到右时，环绕数减1。处理完图形的所有相关边之后，若环绕数为非零，则p为内部点，否则，p是外部点。</td>
    </tr>
  </tbody>
</table>

<p>接下来我们先了解一下两种判断方法是如何工作的。</p>

<h4 id="奇偶规则even-odd-rule">奇偶规则(Even-Odd Rule)</h4>

<p>这一个比较简单，也容易理解，直接用一个简单示例来说明。</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071451.jpg?gcssloop" alt="" /></p>

<p>在上图中有一个四边形，我们选取了三个点来判断这些点是否在图形内部。</p>

<blockquote>

  <p>P1: 从P1发出一条射线，发现图形与该射线相交边数为0，偶数，故P1点在图形外部。<br />
P2: 从P2发出一条射线，发现图形与该射线相交边数为1，奇数，故P2点在图形内部。<br />
P3: 从P3发出一条射线，发现图形与该射线相交边数为2，偶数，故P3点在图形外部。<br /></p>
</blockquote>

<h4 id="非零环绕数规则non-zero-winding-number-rule">非零环绕数规则(Non-Zero Winding Number Rule)</h4>

<p>非零环绕数规则相对来说比较难以理解一点。</p>

<p>我们在之前的文章 <a href="http://www.gcssloop.com/customview/Path_Basic/">Path之基本操作</a> 中我们了解到，在给Path中添加图形时需要指定图形的添加方式，是用顺时针还是逆时针，另外我们不论是使用lineTo，quadTo，cubicTo还是其他连接线的方法，都是从一个点连接到另一个点，换言之，<strong>Path中任何线段都是有方向性的</strong>，这也是使用非零环绕数规则的基础。</p>

<p>我们依旧用一个简单的例子来说明非零环绕数规则的用法:</p>

<blockquote>
  <p><strong>PS: 注意图形中线段的方向性!</strong></p>
</blockquote>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071452.jpg?gcssloop" alt="" /></p>

<blockquote>

  <p>P1: 从P1点发出一条射线，沿射线防线移动，并没有与边相交点部分，环绕数为0，故P1在图形外边。<br />
P2: 从P2点发出一条射线，沿射线方向移动，与图形点左侧边相交，该边从左到右穿过穿过射线，环绕数－1，最终环绕数为－1，故P2在图形内部。<br />
P3: 从P3点发出一条射线，沿射线方向移动，在第一个交点处，底边从右到左穿过射线，环绕数＋1，在第二个交点处，右侧边从左到右穿过射线，环绕数－1，最终环绕数为0，故P3在图形外部。<br /></p>
</blockquote>

<p>通常，这两种方法的判断结果是相同的，但也存在两种方法判断结果不同的情况，如下面这种情况：</p>

<blockquote>
  <p>注意图形线段的方向，就不详细解释了，用上面的方法进行判断即可。</p>
</blockquote>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071453.jpg?gcssloop" alt="" /></p>

<h4 id="自相交图形">自相交图形</h4>

<p><strong>自相交图形定义：多边形在平面内除顶点外还有其他公共点。</strong></p>

<p>简单的提一下自相交图形，了解概念即可，下图就是一个简单的自相交图形：</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071454.jpg?gcssloop" alt="" /></p>

<h4 id="android中的填充模式">Android中的填充模式</h4>

<p>Android中的填充模式有四种，是封装在Path中的一个枚举。</p>

<table>
  <thead>
    <tr>
      <th>模式</th>
      <th>简介</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>EVEN_ODD</td>
      <td>奇偶规则</td>
    </tr>
    <tr>
      <td>INVERSE_EVEN_ODD</td>
      <td>反奇偶规则</td>
    </tr>
    <tr>
      <td>WINDING</td>
      <td>非零环绕数规则</td>
    </tr>
    <tr>
      <td>INVERSE_WINDING</td>
      <td>反非零环绕数规则</td>
    </tr>
  </tbody>
</table>

<p>我们可以看到上面有四种模式，分成两对，例如 “奇偶规则” 与 “反奇偶规则” 是一对，它们之间有什么关系呢？</p>

<p>Inverse 和含义是“相反，对立”，说明反奇偶规则刚好与奇偶规则相反，例如对于一个矩形而言，使用奇偶规则会填充矩形内部，而使用反奇偶规则会填充矩形外部，这个会在后面示例中代码展示两者对区别。</p>

<h4 id="android与填充模式相关的方法">Android与填充模式相关的方法</h4>

<blockquote>
  <p>这些都是Path中的方法。</p>
</blockquote>

<table>
  <thead>
    <tr>
      <th>方法</th>
      <th>作用</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>setFillType</td>
      <td>设置填充规则</td>
    </tr>
    <tr>
      <td>getFillType</td>
      <td>获取当前填充规则</td>
    </tr>
    <tr>
      <td>isInverseFillType</td>
      <td>判断是否是反向(INVERSE)规则</td>
    </tr>
    <tr>
      <td>toggleInverseFillType</td>
      <td>切换填充规则(即原有规则与反向规则之间相互切换)</td>
    </tr>
  </tbody>
</table>

<h4 id="示例演示">示例演示：</h4>

<p>本演示着重于帮助理解填充模式中的一些难点和易混淆的问题，对于一些比较简单的问题，读者可自行验证，本文中不会过多赘述。</p>

<h5 id="奇偶规则与反奇偶规则">奇偶规则与反奇偶规则</h5>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">mDeafultPaint</span><span class="o">.</span><span class="na">setStyle</span><span class="o">(</span><span class="n">Paint</span><span class="o">.</span><span class="na">Style</span><span class="o">.</span><span class="na">FILL</span><span class="o">);</span>                   <span class="c1">// 设置画布模式为填充</span>

<span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="n">mViewWidth</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">mViewHeight</span> <span class="o">/</span> <span class="mi">2</span><span class="o">);</span>          <span class="c1">// 移动画布(坐标系)</span>

<span class="n">Path</span> <span class="n">path</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>                                     <span class="c1">// 创建Path</span>

<span class="c1">//path.setFillType(Path.FillType.EVEN_ODD);                   // 设置Path填充模式为 奇偶规则</span>
<span class="n">path</span><span class="o">.</span><span class="na">setFillType</span><span class="o">(</span><span class="n">Path</span><span class="o">.</span><span class="na">FillType</span><span class="o">.</span><span class="na">INVERSE_EVEN_ODD</span><span class="o">);</span>            <span class="c1">// 反奇偶规则</span>

<span class="n">path</span><span class="o">.</span><span class="na">addRect</span><span class="o">(-</span><span class="mi">200</span><span class="o">,-</span><span class="mi">200</span><span class="o">,</span><span class="mi">200</span><span class="o">,</span><span class="mi">200</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CW</span><span class="o">);</span>         <span class="c1">// 给Path中添加一个矩形</span>
</code></pre>
</div>

<p>下面两张图片分别是在奇偶规则于反奇偶规则的情况下绘制的结果，可以看出其填充的区域刚好相反：</p>

<blockquote>
  <p>PS: 白色为背景色，黑色为填充色。</p>
</blockquote>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-71455.jpg?gcssloop" alt="" />
<img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071455.jpg?gcssloop" alt="" /></p>

<h5 id="图形边的方向对非零奇偶环绕数规则填充结果的影响">图形边的方向对非零奇偶环绕数规则填充结果的影响</h5>

<p>我们之前讨论过给Path添加图形时顺时针与逆时针的作用，除了上次讲述的方便记录外，就是本文所涉及的另外一个重要作用了: <strong>“作为非零环绕数规则的判断依据。”</strong></p>

<p>通过前面我们已经大致了解了在图形边的方向会如何影响到填充效果，我们这里验证一下:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">mDeafultPaint</span><span class="o">.</span><span class="na">setStyle</span><span class="o">(</span><span class="n">Paint</span><span class="o">.</span><span class="na">Style</span><span class="o">.</span><span class="na">FILL</span><span class="o">);</span>                   <span class="c1">// 设置画笔模式为填充</span>

<span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="n">mViewWidth</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">mViewHeight</span> <span class="o">/</span> <span class="mi">2</span><span class="o">);</span>          <span class="c1">// 移动画布(坐系)</span>

<span class="n">Path</span> <span class="n">path</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>                                     <span class="c1">// 创建Path</span>

<span class="c1">// 添加小正方形 (通过这两行代码来控制小正方形边的方向,从而演示不同的效果)</span>
<span class="c1">// path.addRect(-200, -200, 200, 200, Path.Direction.CW);</span>
<span class="n">path</span><span class="o">.</span><span class="na">addRect</span><span class="o">(-</span><span class="mi">200</span><span class="o">,</span> <span class="o">-</span><span class="mi">200</span><span class="o">,</span> <span class="mi">200</span><span class="o">,</span> <span class="mi">200</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CCW</span><span class="o">);</span>

<span class="c1">// 添加大正方形</span>
<span class="n">path</span><span class="o">.</span><span class="na">addRect</span><span class="o">(-</span><span class="mi">400</span><span class="o">,</span> <span class="o">-</span><span class="mi">400</span><span class="o">,</span> <span class="mi">400</span><span class="o">,</span> <span class="mi">400</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CCW</span><span class="o">);</span>

<span class="n">path</span><span class="o">.</span><span class="na">setFillType</span><span class="o">(</span><span class="n">Path</span><span class="o">.</span><span class="na">FillType</span><span class="o">.</span><span class="na">WINDING</span><span class="o">);</span>                    <span class="c1">// 设置Path填充模式为非零环绕规则</span>

<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">path</span><span class="o">,</span> <span class="n">mDeafultPaint</span><span class="o">);</span>                       <span class="c1">// 绘制Path</span>
</code></pre>
</div>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071458.jpg?gcssloop" alt="" />
<img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071500.jpg?gcssloop" alt="" /></p>

<h3 id="布尔操作api19">布尔操作(API19)</h3>

<p>布尔操作与我们中学所学的集合操作非常像，只要知道集合操作中等交集，并集，差集等操作，那么理解布尔操作也是很容易的。</p>

<p><strong>布尔操作是两个Path之间的运算，主要作用是用一些简单的图形通过一些规则合成一些相对比较复杂，或难以直接得到的图形</strong>。</p>

<p>如太极中的阴阳鱼，如果用贝塞尔曲线制作的话，可能需要六段贝塞尔曲线才行，而在这里我们可以用四个Path通过布尔运算得到，而且会相对来说更容易理解一点。</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-71501.jpg?gcssloop" alt="" /></p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="n">mViewWidth</span> <span class="o">/</span> <span class="mi">2</span><span class="o">,</span> <span class="n">mViewHeight</span> <span class="o">/</span> <span class="mi">2</span><span class="o">);</span>

<span class="n">Path</span> <span class="n">path1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>
<span class="n">Path</span> <span class="n">path2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>
<span class="n">Path</span> <span class="n">path3</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>
<span class="n">Path</span> <span class="n">path4</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>

<span class="n">path1</span><span class="o">.</span><span class="na">addCircle</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">200</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CW</span><span class="o">);</span>
<span class="n">path2</span><span class="o">.</span><span class="na">addRect</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="o">-</span><span class="mi">200</span><span class="o">,</span> <span class="mi">200</span><span class="o">,</span> <span class="mi">200</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CW</span><span class="o">);</span>
<span class="n">path3</span><span class="o">.</span><span class="na">addCircle</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="o">-</span><span class="mi">100</span><span class="o">,</span> <span class="mi">100</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CW</span><span class="o">);</span>
<span class="n">path4</span><span class="o">.</span><span class="na">addCircle</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">100</span><span class="o">,</span> <span class="mi">100</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CCW</span><span class="o">);</span>


<span class="n">path1</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path2</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">DIFFERENCE</span><span class="o">);</span>
<span class="n">path1</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path3</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">UNION</span><span class="o">);</span>
<span class="n">path1</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path4</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">DIFFERENCE</span><span class="o">);</span>

<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">path1</span><span class="o">,</span> <span class="n">mDeafultPaint</span><span class="o">);</span>
</code></pre>
</div>

<p>前面演示了布尔运算的作用，接下来我们了解一下布尔运算的核心:布尔逻辑。</p>

<p>Path的布尔运算有五种逻辑，如下:</p>

<table>
  <thead>
    <tr>
      <th>逻辑名称</th>
      <th>类比</th>
      <th>说明</th>
      <th>示意图</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>DIFFERENCE</td>
      <td>差集</td>
      <td>Path1中减去Path2后剩下的部分</td>
      <td><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071502.jpg?gcssloop" alt="" /></td>
    </tr>
    <tr>
      <td>REVERSE_DIFFERENCE</td>
      <td>差集</td>
      <td>Path2中减去Path1后剩下的部分</td>
      <td><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071503.jpg?gcssloop" alt="" /></td>
    </tr>
    <tr>
      <td>INTERSECT</td>
      <td>交集</td>
      <td>Path1与Path2相交的部分</td>
      <td><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-71504.jpg?gcssloop" alt="" /></td>
    </tr>
    <tr>
      <td>UNION</td>
      <td>并集</td>
      <td>包含全部Path1和Path2</td>
      <td><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071505.jpg?gcssloop" alt="" /></td>
    </tr>
    <tr>
      <td>XOR</td>
      <td>异或</td>
      <td>包含Path1与Path2但不包括两者相交的部分</td>
      <td><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071506.jpg?gcssloop" alt="" /></td>
    </tr>
  </tbody>
</table>

<h4 id="布尔运算方法">布尔运算方法</h4>

<p>通过前面到理论知识铺垫，相信大家对布尔运算已经有了基本的认识和理解，下面我们用代码演示一下布尔运算:</p>

<p>在Path中的布尔运算有两个方法</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">boolean</span> <span class="nf">op</span> <span class="o">(</span><span class="n">Path</span> <span class="n">path</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span> <span class="n">op</span><span class="o">)</span>
<span class="kt">boolean</span> <span class="nf">op</span> <span class="o">(</span><span class="n">Path</span> <span class="n">path1</span><span class="o">,</span> <span class="n">Path</span> <span class="n">path2</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span> <span class="n">op</span><span class="o">)</span>
</code></pre>
</div>

<p>两个方法中的返回值用于判断布尔运算是否成功，它们使用方法如下:</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="c1">// 对 path1 和 path2 执行布尔运算，运算方式由第二个参数指定，运算结果存入到path1中。</span>
<span class="n">path1</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path2</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">DIFFERENCE</span><span class="o">);</span>

<span class="c1">// 对 path1 和 path2 执行布尔运算，运算方式由第三个参数指定，运算结果存入到path3中。</span>
<span class="n">path3</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path1</span><span class="o">,</span> <span class="n">path2</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">DIFFERENCE</span><span class="o">)</span>
</code></pre>
</div>

<h4 id="布尔运算示例">布尔运算示例</h4>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-71507.jpg?gcssloop" alt="" /></p>

<p>代码：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">80</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">r</span> <span class="o">=</span> <span class="mi">100</span><span class="o">;</span>

<span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="mi">250</span><span class="o">,</span><span class="mi">0</span><span class="o">);</span>

<span class="n">Path</span> <span class="n">path1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>
<span class="n">Path</span> <span class="n">path2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>
<span class="n">Path</span> <span class="n">pathOpResult</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>

<span class="n">path1</span><span class="o">.</span><span class="na">addCircle</span><span class="o">(-</span><span class="n">x</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">r</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CW</span><span class="o">);</span>
<span class="n">path2</span><span class="o">.</span><span class="na">addCircle</span><span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">r</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CW</span><span class="o">);</span>

<span class="n">pathOpResult</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path1</span><span class="o">,</span><span class="n">path2</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">DIFFERENCE</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">200</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawText</span><span class="o">(</span><span class="s">"DIFFERENCE"</span><span class="o">,</span> <span class="mi">240</span><span class="o">,</span><span class="mi">0</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">pathOpResult</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>

<span class="n">pathOpResult</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path1</span><span class="o">,</span><span class="n">path2</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">REVERSE_DIFFERENCE</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">300</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawText</span><span class="o">(</span><span class="s">"REVERSE_DIFFERENCE"</span><span class="o">,</span> <span class="mi">240</span><span class="o">,</span><span class="mi">0</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">pathOpResult</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>

<span class="n">pathOpResult</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path1</span><span class="o">,</span><span class="n">path2</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">INTERSECT</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">300</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawText</span><span class="o">(</span><span class="s">"INTERSECT"</span><span class="o">,</span> <span class="mi">240</span><span class="o">,</span><span class="mi">0</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">pathOpResult</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>

<span class="n">pathOpResult</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path1</span><span class="o">,</span><span class="n">path2</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">UNION</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">300</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawText</span><span class="o">(</span><span class="s">"UNION"</span><span class="o">,</span> <span class="mi">240</span><span class="o">,</span><span class="mi">0</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">pathOpResult</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>

<span class="n">pathOpResult</span><span class="o">.</span><span class="na">op</span><span class="o">(</span><span class="n">path1</span><span class="o">,</span><span class="n">path2</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Op</span><span class="o">.</span><span class="na">XOR</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">300</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawText</span><span class="o">(</span><span class="s">"XOR"</span><span class="o">,</span> <span class="mi">240</span><span class="o">,</span><span class="mi">0</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">pathOpResult</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>
</code></pre>
</div>

<h3 id="计算边界">计算边界</h3>

<p>这个方法主要作用是计算Path所占用的空间以及所在位置,方法如下：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">computeBounds</span> <span class="o">(</span><span class="n">RectF</span> <span class="n">bounds</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">exact</span><span class="o">)</span>
</code></pre>
</div>

<p>它有两个参数：</p>

<table>
  <thead>
    <tr>
      <th>参数</th>
      <th>作用</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>bounds</td>
      <td>测量结果会放入这个矩形</td>
    </tr>
    <tr>
      <td>exact</td>
      <td>是否精确测量，目前这一个参数作用已经废弃，一般写true即可。</td>
    </tr>
  </tbody>
</table>

<p>关于exact如有疑问可参见Google官方的提交记录<a href="https://code.google.com/p/android/issues/detail?id=4070">Path.computeBounds()</a></p>

<h4 id="计算边界示例">计算边界示例</h4>

<p>计算path边界的一个简单示例.</p>

<p><img src="http://gcsblog.oss-cn-shanghai.aliyuncs.com/blog/2019-04-29-071507.jpg?gcssloop" alt="" /></p>

<p>代码：</p>

<div class="language-java highlighter-rouge"><pre class="highlight"><code><span class="c1">// 移动canvas,mViewWidth与mViewHeight在 onSizeChanged 方法中获得</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="n">mViewWidth</span><span class="o">/</span><span class="mi">2</span><span class="o">,</span><span class="n">mViewHeight</span><span class="o">/</span><span class="mi">2</span><span class="o">);</span>

<span class="n">RectF</span> <span class="n">rect1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">RectF</span><span class="o">();</span>              <span class="c1">// 存放测量结果的矩形</span>

<span class="n">Path</span> <span class="n">path</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Path</span><span class="o">();</span>                 <span class="c1">// 创建Path并添加一些内容</span>
<span class="n">path</span><span class="o">.</span><span class="na">lineTo</span><span class="o">(</span><span class="mi">100</span><span class="o">,-</span><span class="mi">50</span><span class="o">);</span>
<span class="n">path</span><span class="o">.</span><span class="na">lineTo</span><span class="o">(</span><span class="mi">100</span><span class="o">,</span><span class="mi">50</span><span class="o">);</span>
<span class="n">path</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="n">path</span><span class="o">.</span><span class="na">addCircle</span><span class="o">(-</span><span class="mi">100</span><span class="o">,</span><span class="mi">0</span><span class="o">,</span><span class="mi">100</span><span class="o">,</span> <span class="n">Path</span><span class="o">.</span><span class="na">Direction</span><span class="o">.</span><span class="na">CW</span><span class="o">);</span>

<span class="n">path</span><span class="o">.</span><span class="na">computeBounds</span><span class="o">(</span><span class="n">rect1</span><span class="o">,</span><span class="kc">true</span><span class="o">);</span>         <span class="c1">// 测量Path</span>

<span class="n">canvas</span><span class="o">.</span><span class="na">drawPath</span><span class="o">(</span><span class="n">path</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>    <span class="c1">// 绘制Path</span>

<span class="n">mDeafultPaint</span><span class="o">.</span><span class="na">setStyle</span><span class="o">(</span><span class="n">Paint</span><span class="o">.</span><span class="na">Style</span><span class="o">.</span><span class="na">STROKE</span><span class="o">);</span>
<span class="n">mDeafultPaint</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">Color</span><span class="o">.</span><span class="na">RED</span><span class="o">);</span>
<span class="n">canvas</span><span class="o">.</span><span class="na">drawRect</span><span class="o">(</span><span class="n">rect1</span><span class="o">,</span><span class="n">mDeafultPaint</span><span class="o">);</span>   <span class="c1">// 绘制边界</span>
</code></pre>
</div>

<h3 id="重置路径">重置路径</h3>

<p>重置Path有两个方法，分别是reset和rewind，两者区别主要有一下两点：</p>

<table>
  <thead>
    <tr>
      <th>方法</th>
      <th style="text-align: center">是否保留FillType设置</th>
      <th style="text-align: center">是否保留原有数据结构</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>reset</td>
      <td style="text-align: center">是</td>
      <td style="text-align: center">否</td>
    </tr>
    <tr>
      <td>rewind</td>
      <td style="text-align: center">否</td>
      <td style="text-align: center">是</td>
    </tr>
  </tbody>
</table>

<p><strong>这个两个方法应该何时选择呢？</strong></p>

<p>选择权重: FillType &gt; 数据结构</p>

<p><em>因为“FillType”影响的是显示效果，而“数据结构”影响的是重建速度。</em></p>

<h2 id="总结">总结</h2>

<p>Path中常用的方法到此已经结束，希望能够帮助大家加深对Path对理解运用，让大家能够用Path愉快的玩耍。(￣▽￣)</p>

<p>(,,• ₃ •,,)</p>

<h4 id="ps-由于本人水平有限某些地方可能存在误解或不准确如果你对此有疑问可以提交issues进行反馈">PS: 由于本人水平有限，某些地方可能存在误解或不准确，如果你对此有疑问可以提交Issues进行反馈。</h4>

<h2 id="about">About</h2>

<p><a href="http://www.gcssloop.com/customview/CustomViewIndex">本系列相关文章</a></p>

<p>作者微博: <a href="http://weibo.com/GcsSloop">GcsSloop</a></p>

<h2 id="参考资料">参考资料</h2>

<p><a href="https://developer.android.com/reference/android/graphics/Path.html">Path</a><br />
<a href="https://en.wikipedia.org/wiki/Nonzero-rule">维基百科－Nonzero-rule</a><br />
<a href="http://ghui.me/post/2015/10/android-graphics-path/">android绘图之Path总结</a><br />
<a href="https://zh.wikipedia.org/wiki/%E5%B8%83%E5%B0%94%E9%80%BB%E8%BE%91">布尔逻辑</a><br />
<a href="https://code.google.com/p/android/issues/detail?id=4070">GoogleCode－Path.computeBounds()</a><br />
<a href="http://stackoverflow.com/questions/11505617/path-reset-vs-path-rewind">Path.reset vs Path.rewind</a><br /></p>


    <hr>
  </section>
</article>

<!--广告-->

<!--
<div>
<a href="https://m.aliyun.com/act/team1111/?spm=5176.11533457.1089570.5.424777e3AF8WOJ&userCode=hn5smxtw#/" target="_blank"><img src="/assets/aliyun/1111-980-120.jpg" width="100%"></a>
</div>
-->
<!--捐赠晶石-->
<section class="contribute">
    <script type="text/javascript"> 
      function toggle() {
        var con = document.getElementById("contribute");
        if (con.style.display == "none") {
          con.style.display = "block";
        } else {
          con.style.display = "none";
        }
      }
    </script> 
    <blockquote style="background-color:#F5F5F5; padding: 10px 20px 20px 10px; margin:0px" >
      <h4> 如果你觉得我的文章对你有帮助的话，欢迎赞助一些服务器费用! </h4>
      <p></p>
      <a id=“btn-toggle-contribute” class="btn-contribute" onclick="toggle()" >¥ 点击赞助</a>
      <br>
      <div id="contribute" style="display:none;">
        <p align="center" >
        <img src="/assets/images/wechat.png" alt="微信">
        <img src="/assets/images/alipay.png" alt="支付宝">
        </p>
        <p align="left" >
          <b>感谢所有支持我的魔法师，所有支持过我的魔法师都可以通过微信(GcsSloop)联系我，获赠我的付费专栏！</b>
          <!--
          <a href="/contribute">点击这里查看捐赠者名单。</a>
          -->
        </p>
      </div>
    </blockquote>
</section>
<div>
  <h2>欢迎关注我的微信公众号</h2>
  <img src="/assets/images/banner.jpg" width="100%">
</div>

<!--阅读更多-->
<section class="read-more">
  
  
  <div class="read-more-item">
    <span class="read-more-item-dim">最近的文章</span>
    <h2 class="post-list__post-title post-title"><a href="/customview/Path_PathMeasure" title="link to 安卓自定义View进阶-PathMeasure">安卓自定义View进阶-PathMeasure</a></h2>
    <p class="excerpt">可以看到，在经过 Path之基本操作Path之贝塞尔曲线 和 Path之完结篇 后， Path中各类方法基本上都讲完了，表格中还没有讲解到到方法就是矩阵变换了，难道本篇终于要讲矩阵了？非也，矩阵...&hellip;</p>
    <div class="post-list__meta">
      <time datetime="2016-06-02 00:00:00 +0800" class="post-list__meta--date date">2016-06-02</time> &#8226; <span class="post-list__meta--tags tags">CustomView</span>
      <br/><br/>
      <a style="float:none; margin:0 auto;" class="btn-border-small" href=/customview/Path_PathMeasure>继续阅读</a></div>
   </div>
   
   
   
   
   <div class="read-more-item">
       <span class="read-more-item-dim">更早的文章</span>
       <h2 class="post-list__post-title post-title"><a href="/customview/Path_Bezier" title="link to 安卓自定义View进阶-Path之贝塞尔曲线">安卓自定义View进阶-Path之贝塞尔曲线</a></h2>
       <p class="excerpt">在上一篇文章Path之基本操作中我们了解了Path的基本使用方法，本次了解Path中非常非常非常重要的内容-贝塞尔曲线。一.Path常用方法表  为了兼容性(偷懒) 本表格中去除了在API21(...&hellip;</p>
       <div class="post-list__meta">
          <time datetime="2016-04-29 00:00:00 +0800" class="post-list__meta--date date">2016-04-29</time> &#8226; <span class="post-list__meta--tags tags">CustomView</span>
          <br/><br/>
          <a style="float:none; margin:0 auto;" class="btn-border-small" href=/customview/Path_Bezier>继续阅读</a>
       </div>
   </div>
   
</section>

<!--网易云跟帖-->
<!--
<div id="cloud-tie-wrapper" class="cloud-tie-wrapper"></div>
<script src="https://img1.cache.netease.com/f2e/tie/yun/sdk/loader.js"></script>
<script>
var cloudTieConfig = {
  url: document.location.href, 
  sourceId: "",
  productKey: "a85dba2840134721a7b69a15b2e0f217",
  target: "cloud-tie-wrapper"
};
var yunManualLoad = true;
Tie.loader("aHR0cHM6Ly9hcGkuZ2VudGllLjE2My5jb20vcGMvbGl2ZXNjcmlwdC5odG1s", true);
</script>
-->

<style type="text/css">
.isso-comment > div.avatar {
    border: 0px;
    box-shadow: none;
    display: block;
    float: left;
    width: 7%;
    margin: 3px 15px 0 0;
}
.isso-postbox > .form-wrapper > .auth-section .post-action > input {
    border-radius: 6px;
    padding: 6px;
    padding-left: 16px;
    padding-right: 16px;
    border: 1px solid #CCC;
    background-color: #D58D44;
    cursor: pointer;
    outline: 0;
    color: #fff;
    size: 10;
    line-height: 1.4em;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.isso-postbox > .form-wrapper > .auth-section .post-action > input:hover {
    background-color: #272822;
}
.isso-postbox > .form-wrapper > .auth-section .post-action > input:active {
    background-color: #986530;
}
</style>

<section id="isso-thread"></section>

<script data-isso="//47.52.58.34:1234/"
        data-isso-css="true"
        data-isso-lang="zh"
        data-isso-reply-to-self="false"
        data-isso-require-author="false"
        data-isso-require-email="false"
        data-isso-max-comments-top="10"
        data-isso-max-comments-nested="5"
        data-isso-reveal-on-click="5"
        data-isso-avatar="true"
        data-isso-avatar-bg="#f0f0f0"
        data-isso-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..."
        data-isso-vote="true"
        data-vote-levels=""
        src="//47.52.58.34:1234/js/embed.min.js">
        </script>

<!--
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
-->
<!-- OneV's Den -->
<!--
<ins class="adsbygoogle"
     style="display:block"
     data-ad-client="ca-pub-3324997515191619"
     data-ad-slot="9170309685"
     data-ad-format="auto"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
-->

            <section class="footer">
    <footer>
    	<span class="footer__copyright">本站点采用<a rel="license" href="https://creativecommons.org/licenses/by-nc-nd/4.0/deed.zh" target="_blank">知识共享 署名-非商业性使用-禁止演绎 4.0 国际 许可协议</a></span>
        <span class="footer__copyright">本站由 <a href="http://www.GcsSloop.com">@GcsSloop</a> 创建，采用 <a href="https://github.com/GcsSloop/Gcs-Vno-Jekyll" target="_blank">Gcs-Vno-Jekyll</a> 作为主题。<span id="busuanzi_container_site_pv"> 总访问量 <span id="busuanzi_value_site_pv"></span> 次</span> - &copy; 2019</span>
        <span class="footer__sitemap, footer__copyright"><a href="http://www.gcssloop.com/sitemap.xml" target="_blank">Site Map</a>
        <a href="http://www.gcssloop.com/vip" target="_blank">vip</a></span>
    </footer>
</section>

        </div>
    </div>
    
    <script type="text/javascript" src="//code.jquery.com/jquery-1.11.3.min.js"></script>

<script type="text/javascript" src="/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

<script type="text/javascript" src="/js/main.js"></script>

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-82493667-1', 'auto');
  ga('send', 'pageview');

</script>

    
  </body>

</html>
